package plus.decl;

import java.util.*;

import plus.FEnv;
import plus.Gripe;
import plus.Module;
import plus.TEnv;
import plus.Uni;
import plus.VScope;
import plus.run.*;
import plus.stmt.Statement;

public class Program extends Unit {
	final Subroutine main;
	public Program(String name, List<D_Import> imports, DeclBucket decls, Statement stmts) {
		super(name, imports);
		this.main = new Subroutine(decls, stmts);
	}
	@Override public void compile() {
		// Loader is ALREADY initialized. It loaded THIS PROGRAM!!!
		// Prepare type inference and binding environment
		Uni.prepare(imports);
		// This part is specific to class Program:
		VScope.enterBlock();
		TEnv.enterSub();
		Uni.pushFE(new FEnv());
		main.threadScope(Loader.global);
		Uni.popFE();
		if (Uni.converge()) {
			VM.pc = Emit.org;
			Loader.compileLoadingSequence();
			Emit.asm(VM.PUSHBP);
			main.entryPoint.JSR();
			Emit.asm(VM.BRK);
			main.scheduleCompile();
			Subroutine.compileAll();
		} else {
			System.err.println("While Type-Checking "+__FILE__);
			System.err.println("Failed to Converge:");
			Uni.reportConvergenceFailure();
			Gripe.gripe("Type Mismatch");
		}
	}
	@Override
	public Module asModule() {
		throw new Gripe("Expected a module, found a program instead at "+__FILE__);
	}
}
